package ms.unicorn.modellanguage;

import java.util.ArrayList;
import java.util.List;

import ms.unicorn.util.ConfigUtil;
import ms.unicorn.util.ErrorHandler;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.gmf.runtime.emf.type.core.IElementType;
import org.eclipse.gmf.runtime.emf.type.core.IHintedType;
import org.eclipse.gmf.runtime.emf.type.core.ISpecializationType;

public abstract class LanguageElement {
	
	private String id, name;
	private IElementType elementType;
	private IModelLanguage language;
	private List<ElementAnnotation> annotations;
	private DecoratorProxyList decorators;
	
	protected LanguageElement(IModelLanguage language) {
		this.language = language;
		annotations = new ArrayList<ElementAnnotation>();
		decorators = new DecoratorProxyList();
	}
	
	protected LanguageElement(IModelLanguage language, IConfigurationElement config) {
		this(language);
		load(config);
	}
	
	protected void load(IConfigurationElement config) {
		id = ConfigUtil.get(config, "id", id);
		name = ConfigUtil.get(config, "name", name);
		
		try {
			Object helper = language.getCachedObject(config.getAttribute("helper"));
			if (helper == null)
				language.setCachedObject(helper = config.createExecutableExtension("helper"));
			setEditHelperAdvice((IElementEditHelperAdvice) helper);
			// create element annotation
			for(IConfigurationElement subchild: config.getChildren()) {
				String childname = subchild.getName();
				processConfigItem(subchild, childname);
			}
					
		} catch (CoreException e1) {
			ErrorHandler.handleException(e1);
		}
	}

	protected void processConfigItem(IConfigurationElement config,
			String itemName) {
		if ("annotation".equals(itemName))
			annotations.add(new ElementAnnotation(config));
		else if ("decorator".equalsIgnoreCase(itemName))
			getDecorators().add(new DecoratorProxy(config));
	}

	protected ISpecializationType createElementType() {
		IElementType baseType = getBaseType();
		HintedSpecializationType result = new HintedSpecializationType(
				id, null, name, 
				new IElementType[] {baseType},
				null, 
				null, 
				getEditHelperAdvice());
		result.setElement(this);
		result.setLanguage(language);
		result.setSemanticHint(((IHintedType) baseType).getSemanticHint());
		return result;
	}
	
	public boolean acceptChild(LanguageElement element) {
		return false;
	}
	
	protected IElementType getBaseType() {
		return null;
	}
	
	public String getId() {
		return id;
	}
	
	public void setId(String id) {
		this.id = id;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getName() {
		return name;
	}

	public void setEditHelperAdvice(IElementEditHelperAdvice advice) {
		
	}

	public IElementEditHelperAdvice getEditHelperAdvice() {
		return null;
	}

	public void setElementType(IElementType elementType) {
		this.elementType = elementType;
	}

	public IElementType getElementType() {
		return elementType != null ? elementType : (elementType = createElementType());
	}

	public IModelLanguage getLanguage() {
		return this.language;
	}

	public List<ElementAnnotation> getAnnotations() {
		return annotations;
	}

	public List<DecoratorProxy> getDecorators() {
		return decorators;
	}
}
